package com.mathdroid.model.abilities.optimizer;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import javax.swing.SwingWorker;

import com.mathdroid.model.abilities.AbilityTemplate;

/**
 * This optimizer searches for the best priorities of abilities. Each possible
 * combination of priorities is simulated and compared.
 */
public final class AbilityOptimizerDelegate 
extends SwingWorker<AbilityOptimizerResultList, Void> {
	
	/**
	 * The best results that were reached.
	 */
	private AbilityOptimizerResultList results = 
		new AbilityOptimizerResultList();
	
	/**
	 * If the optimizer is willing to fill the queue.
	 */
	private Boolean incoming = true;

	/**
	 * The maximum size of the queue.
	 */
	private static final int MAX_SIZE = 10;
	
	/**
	 * The queue to work through.
	 */
	private LinkedBlockingQueue<AbilityTemplate> queue = 
		new LinkedBlockingQueue<AbilityTemplate>(MAX_SIZE);
	
	/**
	 * Simulates each ability priority list which is added to the queue.
	 * @return The lists with the best results.
	 */
	public AbilityOptimizerResultList getOptimalPriorities() {
		boolean stop = false;

		while (!stop && !this.isCancelled()) {
				AbilityOptimizerResult r = new AbilityOptimizerResult();
				r.setRating(Math.random() * 1000);
				try {
					AbilityTemplate temp = this.queue.take();
					Thread.sleep(10);
					r.setPrio(temp);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				this.results.offer(r);
				
				synchronized (this.incoming) {
					if (!this.incoming && this.queue.isEmpty()) {
						stop = true;
					}
				}
		}
		
		return this.results;
	}

	@Override
	protected AbilityOptimizerResultList doInBackground() throws Exception {
		return this.getOptimalPriorities();
	}
	
	/**
	 * Add an ability list to the queue, if the queue isn't too full.
	 * @param list Ability priority list.
	 * @return if the list was added.
	 */
	public boolean queue(final AbilityTemplate list) {
		boolean added = false;

		try {
			added = this.queue.offer(list, 1, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return added;
	}

	/**
	 * Notify this task if no more lists will be added to the queue.
	 */
	public void finishIt() {
		this.incoming = false;
	}
	
}
